package com.computergames.server.server;

import com.computergames.server.protocol.MessageCodecSharable;
import com.computergames.server.protocol.ProtocolFrameDecoder;
import com.computergames.server.server.handler.*;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.timeout.IdleStateHandler;
import com.computergames.server.config.Config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.net.ssl.SSLException;
import java.io.File;
import java.util.concurrent.*;


@Slf4j
public class ComputerGamesServerImpl implements ComputerGamesServer{
    private final int processor = Runtime.getRuntime().availableProcessors();
    //private final int used = adjustWorkerThreads(new NioEventLoopGroup());
    private static final int DEFAULT_BOSS_THREADS = 1;
    private static final int DEFAULT_WORKER_THREADS = Runtime.getRuntime().availableProcessors() * 2;
    private static final int MAX_WORKER_THREADS = 100;
    private static final int MIN_WORKER_THREADS = 2;
    private static final int LOAD_THRESHOLD = 80; // 负载阈值，超过这个阈值增加线程数
    private static final int ADJUSTMENT_INTERVAL = 5; // 调整间隔时间，单位：秒

    private ScheduledExecutorService scheduler;
    @Override
    public void start() {
        LoggingHandler LOGGING_HANDLER = new LoggingHandler(LogLevel.INFO);
        MessageCodecSharable MESSAGE_CODEC = new MessageCodecSharable();
        LoginPromptMessageHandler LOGIN_PROMPT_HANDLER = new LoginPromptMessageHandler();
        LoginRequestMessageHandler LOGIN_HANDLER = new LoginRequestMessageHandler();
        ModeSelectionRequestMessageHandler MODE_SELECTION_HANDLER = new ModeSelectionRequestMessageHandler();
        StageSelectionRequestMessageHandler STAGE_SELECTION_HANDLER = new StageSelectionRequestMessageHandler();
        HeartBeatDetectionHandler HEART_BEAT_DETECTION_HANDLER = new HeartBeatDetectionHandler();
        ReconnectRequestMessageHandler RECONNECT_HANDLER = new ReconnectRequestMessageHandler();
        JWTAuthHandler JWT_AUTH_HANDLER = new JWTAuthHandler();
        ConnectionTimeHandler connectionTimeHandler = new ConnectionTimeHandler();
        NioEventLoopGroup boss = new NioEventLoopGroup(DEFAULT_BOSS_THREADS);
        NioEventLoopGroup worker = new NioEventLoopGroup(DEFAULT_WORKER_THREADS);
//      NioEventLoopGroup worker = new NioEventLoopGroup(processor*used*(1+(int)connectionTimeHandler.calculateAverageTimes()));

        try {
            File certChainFile = new File("D:\\try\\ComputerGamesServer\\ComputerGamesServer\\src\\main\\resources\\SSL\\server.crt");
            File keyFile = new File("D:\\try\\ComputerGamesServer\\ComputerGamesServer\\src\\main\\resources\\SSL\\pkcs8_server.key");
            File clientRootCertFile = new File("D:\\try\\ComputerGamesServer\\ComputerGamesServer\\src\\main\\resources\\SSL\\client.crt");

            // 构建 SslContext
            SslContext sslCtx = SslContextBuilder.forServer(certChainFile, keyFile)
                    .trustManager(clientRootCertFile)
                    .build();

            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(boss, worker)
                    .channel(NioServerSocketChannel.class)
                    //设置在连接建立之前（服务器触发accept事件之前）能够排队的连接请求数量，根据系统资源进行合理设置
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    //检测底层TCP连接是否存活，在长时间没有数据传输的情况下，系统会自动发送keepalive探测包，保持长连接
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //ch.pipeline().addLast(sslCtx.newHandler(ch.alloc()));
                            ch.pipeline().addLast(new ProtocolFrameDecoder());
                            ch.pipeline().addLast(LOGGING_HANDLER);
                            ch.pipeline().addLast(MESSAGE_CODEC);
                            ch.pipeline().addLast(JWT_AUTH_HANDLER);
                            ch.pipeline().addLast(new IdleStateHandler(0, 0, 0));
                            ch.pipeline().addLast(HEART_BEAT_DETECTION_HANDLER);
                            ch.pipeline().addLast(LOGIN_PROMPT_HANDLER);
                            ch.pipeline().addLast(LOGIN_HANDLER);
                            ch.pipeline().addLast(MODE_SELECTION_HANDLER);
                            ch.pipeline().addLast(STAGE_SELECTION_HANDLER);
                            ch.pipeline().addLast(RECONNECT_HANDLER);
                            //ch.pipeline().addLast(connectionTimeHandler);
                        }
                    });
            ChannelFuture channelFuture = serverBootstrap.bind(Config.getServerPort()).sync();
            channelFuture.channel().closeFuture().sync();
        }catch (InterruptedException e){
            log.error("server error", e);
        } catch (SSLException e) {
            throw new RuntimeException(e);
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }

    private static int adjustWorkerThreads(NioEventLoopGroup worker) {
        int currentThreads = worker.executorCount();

        // 获取当前活跃线程数（自定义监控）
        int activeThreads = customMonitorActiveThreads(worker);
        System.out.println("当前活跃线程数： "+ activeThreads);

        // 计算负载百分比
        int loadPercentage = activeThreads / currentThreads;

//        if (loadPercentage > LOAD_THRESHOLD && currentThreads < MAX_WORKER_THREADS) {
//            // 增加线程数
//            worker.shutdownGracefully();
//            worker = new NioEventLoopGroup(currentThreads + 1);
//            System.out.println("Increased worker threads to: " + worker.executorCount());
//        } else if (loadPercentage < 20 && currentThreads > MIN_WORKER_THREADS) {
//            // 减少线程数
//            worker.shutdownGracefully();
//            worker = new NioEventLoopGroup(currentThreads - 1);
//            System.out.println("Decreased worker threads to: " + worker.executorCount());
//        }
        return loadPercentage;
    }

    private static int customMonitorActiveThreads(NioEventLoopGroup eventLoopGroup) {
        int activeThreads = 0;

        for (int i = 0; i < eventLoopGroup.executorCount(); i++) {
            if (eventLoopGroup.next().inEventLoop()) {
                activeThreads++;
            }
        }

        return activeThreads;
    }
}
